package com.industry.framework.core.snow;

import com.industry.framework.core.context.CoreApplicationContext;

import java.util.concurrent.atomic.AtomicLong;

/**
 * @Author nbZhuozh
 * @Date 2025-05-21  16:30
 **/
public class SnowflakeIdStaticGenerator {
    // 配置参数（可通过启动参数或配置文件设置）
    private static final long WORKER_ID = Long.getLong("snowflake.workerId", 2);
    private static final long DATA_CENTER_ID = Long.getLong("snowflake.dataCenterId", 3);

    // 位分配
    private static final long TIMESTAMP_BITS = 41L;
    private static final long WORKER_ID_BITS = 5L;
    private static final long DATA_CENTER_BITS = 5L;
    private static final long SEQUENCE_BITS = 12L;

    // 最大值计算
    private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
    private static final long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_BITS);
    private static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);

    // 位移计算
    private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATA_CENTER_BITS;
    private static final long DATA_CENTER_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
    private static final long WORKER_SHIFT = SEQUENCE_BITS;

    // 时间起点（可配置）
    private static final long EPOCH = 1609459200000L; // 2021-01-01

    // 单例实例
    private static volatile SnowflakeIdStaticGenerator instance;

    // 原子变量
    private final AtomicLong lastTimestamp = new AtomicLong(-1L);
    private final AtomicLong sequence = new AtomicLong(0);

    // 私有构造函数
    private SnowflakeIdStaticGenerator() {
        validateConfiguration();
    }

    // 获取单例实例（线程安全）
    public static SnowflakeIdStaticGenerator getInstance() {
        if (instance == null) {
            synchronized (SnowflakeIdStaticGenerator.class) {
                if (instance == null) {
                    instance = new SnowflakeIdStaticGenerator();
                }
            }
        }
        return instance;
    }

    // 静态生成方法
    public static long generateId() {
        return getInstance().nextId();
    }

    private long nextId() {
        while (true) {
            long currentTs = System.currentTimeMillis();
            long lastTs = lastTimestamp.get();

            // 处理时钟回拨
            if (currentTs < lastTs) {
                handleClockBackwards(currentTs, lastTs);
            }

            // 同一时间戳处理序列号
            if (currentTs == lastTs) {
                long currSeq = sequence.incrementAndGet() & SEQUENCE_MASK;
                if (currSeq != 0) {
                    return composeId(currentTs, currSeq);
                }
                // 序列溢出，等待下一毫秒
                currentTs = waitNextMillis(currentTs);
            }

            // CAS更新时间戳
            if (lastTimestamp.compareAndSet(lastTs, currentTs)) {
                sequence.set(0);
            }
        }
    }

    private void validateConfiguration() {
        if (WORKER_ID > MAX_WORKER_ID || WORKER_ID < 0) {
            throw new IllegalArgumentException("Invalid worker ID");
        }
        if (DATA_CENTER_ID > MAX_DATA_CENTER_ID || DATA_CENTER_ID < 0) {
            throw new IllegalArgumentException("Invalid data center ID");
        }
    }

    private long composeId(long timestamp, long sequence) {
        return ((timestamp - EPOCH) << TIMESTAMP_SHIFT) |
                (DATA_CENTER_ID << DATA_CENTER_SHIFT) |
                (WORKER_ID << WORKER_SHIFT) |
                sequence;
    }

    private long waitNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            Thread.yield();
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }

    private void handleClockBackwards(long currentTs, long lastTs) {
        long offset = lastTs - currentTs;
        if (offset <= 1000) { // 1秒内的回拨等待
            try {
                Thread.sleep(offset);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        } else {
            throw new RuntimeException("Clock moved backwards beyond threshold");
        }
    }

}
